import router from '@ohos.router';
import observer from '@ohos.arkui.observer';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { UIAbility } from '@kit.AbilityKit'
import {
  PageRouteOpenMode,
  RouterBackOptionsWrapper,
  RouterHandler,
  RouterRequestWrapper,
  RouterResponse,
  RouterResponseError,
  RouterResultStrategy
} from './RouterDefine';

/**
 * 系统router模式的路由管理类。
 */
export class RouterManagerForSystemRouter implements RouterHandler {
  private static sInstance: RouterManagerForSystemRouter

  public static getInstance(): RouterManagerForSystemRouter {
    if (!RouterManagerForSystemRouter.sInstance) {
      RouterManagerForSystemRouter.sInstance = new RouterManagerForSystemRouter()
    }
    return RouterManagerForSystemRouter.sInstance
  }

  currentPageName(): string {
    return router.getState().name
  }

  currentPageIndex(): number {
    return router.getState().index
  }

  /* RouterHandler相关方法 */

  init(uiAbility: UIAbility) {
    this.observerPageLifecycle(uiAbility)
  }

  open(request: RouterRequestWrapper): Promise<RouterResponse> {
    return new Promise((resolve, reject) => {
      this.inject(request)
      let routerPushSuccessFunc = () => {
        request.resolve = resolve;
        request.fromIndex = this.currentPageIndex() - 1 // 页面打开成功后currentPageIndex取到的是页面的index，因此fromIndex需要-1
      }
      let routerPushErrorFunc = (e: ESObject) => {
        console.log(`${e.toString()}`)
        this.remove(request)
        if (e.code == 100004) {
          resolve(RouterResponseError.RequestNotFoundResponsor)
        } else {
          resolve(RouterResponseError.UnknownError)
        }
      }
      if (request.isRouterPath) {
        switch (request?.rawRequest.openMode) {
          case PageRouteOpenMode.replace:
            router.replaceUrl({
              url: request.routeName,
              params: request.params
            }).then(routerPushSuccessFunc).catch(routerPushErrorFunc);
            break;

          default:
            router.pushUrl({
              url: request.routeName,
              params: request.params
            }).then(routerPushSuccessFunc).catch(routerPushErrorFunc);
            break;
        }
      } else {
        switch (request?.rawRequest.openMode) {
          case PageRouteOpenMode.replace:
            router.replaceNamedRoute({
              name: request.routeName,
              params: request.params
            }).then(routerPushSuccessFunc).catch(routerPushErrorFunc);
            break;

          default:
            router.pushNamedRoute({
              name: request.routeName,
              params: request.params
            }).then(routerPushSuccessFunc).catch(routerPushErrorFunc);
            break;
        }
      }
    })
  }

  close(options?: RouterBackOptionsWrapper | undefined): boolean {
    this.resultStrategy = RouterResultStrategy.onPagePop
    if (options) {
      if (options.routeName && options.routeName.length > 0) {
        this.resultStrategy = RouterResultStrategy.onPageShow
        this.backToRouteName = options.routeName
      }
      router.back({ url: options.routeName, params: options.params })
    } else {
      router.back()
    }
    return true
  }

  /* callback相关方法 */

  /**
   * 返回值处理策略
   */
  resultStrategy: RouterResultStrategy = RouterResultStrategy.onPagePop
  /**
   * 将要返回的routeName
   */
  backToRouteName?: string
  backToIndex?: number
  /**
   * 最后一个获取到的回调方法
   */
  lastResolve?: (value: RouterResponse | PromiseLike<RouterResponse>) => void

  observerPageLifecycle(uiAbility: UIAbility) {
    observer.on("routerPageUpdate", uiAbility.context, (routerPageInfo: observer.RouterPageInfo) => {
      hilog.info(0x0000, 'routerPageUpdateTAG',
        "life:" + routerPageInfo.path + ":" + routerPageInfo.name + ":index=" + routerPageInfo.index +
          ":routerStateIndex=" + router.getState().index + ";state:" + routerPageInfo.state);

      let name = routerPageInfo.name
      let fromIndex = routerPageInfo.index - 1
      // 通过监听页面生命周期方法，将系统堆栈和routes保持一致，用来处理返回值回调
      switch (routerPageInfo.state) {
        case observer.RouterPageState.ABOUT_TO_APPEAR:
        // state虽然是ABOUT_TO_APPEAR，但实际上也已经进栈，因此`router.getState().index`获取到的index就是当前页面的index，所以需要-1
          if (!this.hasRequest(name, fromIndex)) {
            let request = this.hasUndefinedRequest(name)
            if (request) {
              request.pageInfo = routerPageInfo
            } else {
              this.inject(new RouterRequestWrapper({ url: "other/" + name }, fromIndex), routerPageInfo)
            }
          }

          break

        case observer.RouterPageState.ON_PAGE_SHOW: {
          if (this.resultStrategy == RouterResultStrategy.onPageShow && name === this.backToRouteName) {
            this.backToIndex = routerPageInfo.index

            // A->B，B返回A时，A页面的ON_PAGE_SHOW比B页面的ABOUT_TO_DISAPPEAR早触发，所以延时执行
            setTimeout(() => {
              const params = router.getParams()
              this.lastResolve?.({
                code: RouterResponseError.Success.code,
                msg: RouterResponseError.Success.msg,
                data: params
              })
            }, 500)
          }
          break
        }

        case observer.RouterPageState.ABOUT_TO_DISAPPEAR: {
          if (this.resultStrategy == RouterResultStrategy.onPagePop) {
            const params = router.getParams()
            const request = this.getRequest(name, fromIndex)
            if (request != undefined) {
              request.request?.resolve?.({
                code: RouterResponseError.Success.code,
                msg: RouterResponseError.Success.msg,
                data: params
              })
            }
          } else {
            // 因为routes中可能存在同名请求，因此需要通过指定的backToIndex，找到对应的请求
            if (fromIndex == this.backToIndex) {
              hilog.info(0x0000, 'routerPageUpdateTAG',
                "找到了callback:backToIndex=" + this.backToIndex + ";index:" + routerPageInfo.index);
              const request = this.getRequest(name, fromIndex)
              if (request != undefined) {
                this.lastResolve = request.request?.resolve
              }
            }
          }

          this.removeRequest(name, fromIndex)
          break
        }

        case observer.RouterPageState.ON_BACK_PRESS: {
          const request = this.getRequest(name, fromIndex)
          if (request != undefined) {
            request.request?.resolve?.({
              code: RouterResponseError.Success.code,
              msg: RouterResponseError.Success.msg
            })
          }

          // 触发ON_BACK_PRESS后还会触发ABOUT_TO_DISAPPEAR状态，但因为request已被删除，所以不会重复触发回调
          this.removeRequest(name, fromIndex)
          break
        }
      }
    })
  }

  private routes: Array<RouterRouteInfo> = new Array()

  private hasRequest(routeName: string, index: number): Boolean {
    let results = this.routes.filter((element) => {
      return element.request?.routeName == routeName && element.request?.fromIndex === index
    })
    return results.length > 0
  }

  private hasUndefinedRequest(routeName: string): RouterRouteInfo | undefined {
    let results = this.routes.filter((element) => {
      return element.request?.routeName == routeName && element.pageInfo === undefined
    })
    return results.pop()
  }

  private getRequest(routeName: string, index: number): RouterRouteInfo | undefined {
    let results = this.routes.filter((element) => {
      return element.request?.routeName == routeName &&
        (index == undefined || (index != undefined && element.request?.fromIndex === index))
    })
    return results.pop()
  }

  private removeRequest(routeName: string, index: number) {
    let info = this.getRequest(routeName, index)
    if (info) {
      this.routes = this.routes.filter((item) => item !== info)
    }
  }

  inject(request: RouterRequestWrapper, pageInfo?: observer.RouterPageInfo) {
    this.routes.push({ request: request, pageInfo: pageInfo });
  }

  remove(request: RouterRequestWrapper) {
    let results = this.routes.filter((element) => {
      return element.request == request
    })
    let info = results.pop()
    if (info) {
      this.routes = this.routes.filter((item) => item !== info)
    }
  }
}

interface RouterRouteInfo {
  request?: RouterRequestWrapper
  pageInfo?: observer.RouterPageInfo
}